package cn.shengchao.examstar.pay.model.service.fy;

import cn.shengchao.examstar.pay.model.service.fy.dto.Parameter;
import cn.shengchao.examstar.pay.model.service.fy.dto.ParameterCollection;
import cn.shengchao.examstar.pay.model.service.fy.request.FuYouAuthUrlParameters;
import cn.shengchao.examstar.pay.model.service.fy.request.FuYouOrderQueryRequest;
import cn.shengchao.examstar.pay.model.service.fy.request.FuYouPreCreateRequest;
import cn.shengchao.examstar.pay.model.service.fy.request.UrlParameterRequest;
import cn.shengchao.examstar.pay.model.service.fy.response.FuYouApiResponse;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Map;

public class FuYouUtil {

    public static FuYouApiResponse createConfig(
            FYrequest fYrequestData, String insPrivateKey, String fyPublicKey) throws Exception {

        FuYouPreCreateRequest preCreateRequest = new FuYouPreCreateRequest(fYrequestData);
        ParameterCollection requestParams = preCreateRequest.toParameterCollection();

        return run(requestParams, "https://spay-mc.fuioupay.com/wxPreCreate", insPrivateKey, fyPublicKey);
    }

    public static FuYouApiResponse run(
            ParameterCollection requestParameters, String url, String insPrivateKey, String fyPublicKey)
            throws Exception {

        String sign = Utils.getSign(requestParameters, insPrivateKey);

        ParameterCollection paramsForXml = new ParameterCollection();
        for(Parameter p : requestParameters) {
            paramsForXml.add(p);
        }
        paramsForXml.add("sign", sign);

        Document doc = DocumentHelper.createDocument();
        Element root = doc.addElement("xml");

        for (Parameter p : paramsForXml) {
            root.addElement(p.getName()).addText(p.getValue() == null ? "" : p.getValue());
        }

        String reqXmlBody = "<?xml version=\"1.0\" encoding=\"" + Const.charset + "\" standalone=\"yes\"?>"
                + doc.getRootElement().asXML();

        System.out.println(
                "==============================待编码请求XML==============================\r\n" + reqXmlBody);

        String encodedReqBody = URLEncoder.encode(reqXmlBody, Const.charset);

        System.out.println(
                "==============================编码后请求字符串==============================\r\n" + encodedReqBody);

        ParameterCollection httpPostParams = new ParameterCollection();
        httpPostParams.add("req", encodedReqBody);

        StringBuffer resultXmlBuffer = new StringBuffer("");
        HttpUtils httpUtils = new HttpUtils();
        httpUtils.post(url, httpPostParams, resultXmlBuffer);

        String decodedRspXml = "";
        if (!resultXmlBuffer.isEmpty()) {
            decodedRspXml = URLDecoder.decode(resultXmlBuffer.toString(), Const.charset);
        }

        System.out.println(
                "==============================响应报文==============================\r\n" + decodedRspXml);

        FuYouApiResponse apiResponse = new FuYouApiResponse(decodedRspXml);

        String signFromServer = apiResponse.getSign();
        if (signFromServer == null || signFromServer.isEmpty()) {
            System.err.println("响应报文中没有签名 (sign is null or empty). API Response Success: " + apiResponse.isSuccess());
            // If the response is successful but no sign, it could be an issue or specific API behavior
            if (apiResponse.isSuccess()) {
                // Depending on strictness, you might throw an error or log a warning
                // For now, let's assume some success responses might not have a sign
                System.out.println("Warning: Successful response received without a signature.");
            } else if (decodedRspXml.isEmpty() && !apiResponse.isSuccess()) {
                // If response is empty and not successful, it's likely a communication error handled by httpPost
                System.out.println("Empty response received and it's not marked as successful.");
            }
            // else, if not successful and no sign, it's an error state from Fuiou often.
        } else {
            if (!Utils.verifySign(apiResponse.getAllParameters(), signFromServer, fyPublicKey)) {
                throw new Exception("富友响应验签失败！");
            }
            System.out.println("富友响应验签成功！");
        }
        return apiResponse;
    }

    public static String wxAuthUrl(
            String baseUrl,
            Map<String, String> merchantParametersMap,
            String insCd,
            String mchntCd,
            String insPrivateKey)
            throws Exception {

        UrlParameterRequest merchantUrlParams = new UrlParameterRequest(merchantParametersMap);
        String mchntRedirectUrl = getRequestUrl(baseUrl, merchantUrlParams.toParameterCollection());

        // Original code had appid as "", so passing it explicitly.
        FuYouAuthUrlParameters authParams = new FuYouAuthUrlParameters(insCd, mchntCd, "1", "", mchntRedirectUrl);
        ParameterCollection authParamCollection = authParams.toParameterCollection();

        String sign = Utils.getSign(authParamCollection, insPrivateKey);

        // Create a new collection for URL building to include the sign
        ParameterCollection finalAuthParamsForUrl = new ParameterCollection();
        for(Parameter p : authParamCollection){
            finalAuthParamsForUrl.add(p);
        }
        finalAuthParamsForUrl.add("sign", sign);

        return getRequestUrl("https://spay-mc.fuioupay.com/oauth2/getOpenid", finalAuthParamsForUrl);
    }

    public static String getRequestUrl(String baseUrl, ParameterCollection params) throws UnsupportedEncodingException {
        StringBuilder requestUrlBuilder = new StringBuilder(baseUrl);
        if (params != null && !params.isEmpty()) {
            requestUrlBuilder.append("?");
            boolean firstParam = true;
            // Create a sorted list of parameters for consistent URL (optional but good practice)
            // List<Parameter> sortedParams = new ArrayList<>(params.getParameters());
            // sortedParams.sort(Comparator.comparing(Parameter::getName));

            for (Parameter p : params) { // Iterate over original order or sortedParams
                if (!firstParam) {
                    requestUrlBuilder.append("&");
                }
                requestUrlBuilder.append(URLEncoder.encode(p.getName(), Const.charset))
                        .append("=")
                        .append(URLEncoder.encode(p.getValue() == null ? "" : p.getValue(), Const.charset));
                firstParam = false;
            }
        }
        return requestUrlBuilder.toString();
    }

    public static FuYouApiResponse queryOrder(
            String tradeNo,
            String insCd,
            String mchntCd,
            String type,
            String insPrivateKey,
            String fyPublicKey)
            throws Exception {

        FuYouOrderQueryRequest queryRequest = new FuYouOrderQueryRequest(tradeNo, insCd, mchntCd, type);
        ParameterCollection requestParams = queryRequest.toParameterCollection();

        return run(requestParams, "https://spay-mc.fuioupay.com/commonQuery", insPrivateKey, fyPublicKey);
    }
}
